import { PropType, VNode, computed, defineComponent, ref, watch, watchEffect } from "vue";
import useTransition from "../use/useTransition";
import { FeatherX } from "cui-vue-icons/feather";

type DrawerAlign = 'right' | 'left' | 'top' | 'bottom';

export interface DrawerProps {
    align?: DrawerAlign; // 抽屉方向
    size?: number; // 抽屉尺寸
    title?: string | VNode; // 标题
    maskCloseable?: boolean; // 是否允许点击遮罩关闭
    hasClose?: boolean; // 是否显示关闭按钮
    escClose?: boolean; // 是否允许按 ESC 关闭
    modelValue?: boolean; // 控制抽屉显示/隐藏
    onClose?: () => void; // 关闭回调
    onShow?: () => void; // 显示回调
    destroyOnClose?: boolean; // 关闭时是否销毁内容
}

export default defineComponent({
    name: 'Drawer',
    props: {
        align: {type: String as PropType<DrawerProps['align']>, default: 'right'},
        size: {type: Number as PropType<DrawerProps['size']>, default: 256},
        title: {type: [String, Object] as PropType<DrawerProps['title']>},
        maskCloseable: {type: Boolean as PropType<DrawerProps['maskCloseable']>, default: true},
        hasClose: {type: Boolean as PropType<DrawerProps['hasClose']>, default: true},
        escClose: {type: Boolean as PropType<DrawerProps['escClose']>},
        modelValue: {type: Boolean as PropType<DrawerProps['modelValue']>, default: false},
        destroyOnClose: {type: Boolean as PropType<DrawerProps['destroyOnClose']>},
    },
    emits: ['close', 'show', 'update:modelValue'],
    setup (props: DrawerProps, { emit, slots }) {
        const visible = ref(props.modelValue); // 控制抽屉显示/隐藏
        const destroyed = ref(props.destroyOnClose && !visible.value); // 是否已销毁内容
        const boxRef = ref<HTMLElement | null>(null); // 抽屉容器引用
        const targetRef = ref<HTMLElement | null>(null); // 抽屉内容引用
        let originBodyOverflow: string; // 保存原始的 body overflow 值

        // 计算抽屉样式
        const drawerStyle = computed(() => {
            const sizeValue = `${props.size}px`;
            return {
                [props.align === 'left' || props.align === 'right' ? 'width' : 'height']: sizeValue,
            };
        });

        // 计算类名
        const classList = computed(() => ({
            'cm-drawer': true,
            [`cm-drawer-${props.align}`]: true,
        }));

        // 初始化过渡效果
        const transition = useTransition({
            el: () => boxRef.value,
            target: () => targetRef.value,
            startClass: 'cm-drawer-visible',
            activeClass: 'cm-drawer-open',
            onLeave: () => {
                emit('close');
                document.body.style.overflow = originBodyOverflow;
                if (props.destroyOnClose) {
                    destroyed.value = true;
                }
            },
            onEnter: () => {
                originBodyOverflow = document.body.style.overflow;
                document.body.style.overflow = 'hidden';
            },
        });

        watch(()=> props.modelValue, (val) => {
            visible.value = val;
        });

        // 监听 visible 变化
        watchEffect(() => {
            const v = visible.value;
            if (v) {
                destroyed.value = false;
                transition.enter();
                emit('show');
            } else {
                transition.leave();
            }
        });

        // 点击遮罩关闭
        const onMaskClick = () => {
            if (props.maskCloseable) {
                onClose();
            }
        };

        // 关闭抽屉
        const onClose = () => {
            visible.value = false;
            emit('update:modelValue', false);
        };

        // 监听 ESC 按键
        const onKeyUp = (e: KeyboardEvent) => {
            if (props.escClose && e.code === 'Escape') {
                onClose();
            }
        };

        return () => <div class={classList.value} ref={boxRef} tab-index={1} onKeyup={onKeyUp}>
            <div class="cm-drawer-mask" onClick={onMaskClick}></div>
            <div class="cm-drawer-wrap" style={drawerStyle.value} ref={targetRef}>
                { props.title && <div class="cm-drawer-title">{props.title}</div> }
                { props.hasClose && <FeatherX class="cm-drawer-close" onClick={onClose}/> }
                <div class="cm-drawer-body">
                    {!destroyed.value && slots.default?.()}
                </div>
            </div>
        </div>;
    }
});
